package com.wb3.meta.api.core.service.impl;

import com.github.binarywang.wxpay.bean.request.WxPayOrderCloseRequest;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.wb3.meta.api.core.dao.GoodsOrdersMapper;
import com.wb3.meta.api.core.model.GoodsOrders;
import com.wb3.meta.api.core.service.GoodsInfoService;
import com.wb3.meta.api.core.service.GoodsOrdersService;
import com.wb3.meta.api.core.service.MyToysService;
import com.wb3.meta.api.core.vo.*;
import com.wb3.meta.common.authentication.RequestHolder;
import com.wb3.meta.common.enums.EnumConstants;
import com.wb3.meta.common.mybatis.DataTableUtil;
import com.wb3.meta.common.pojo.ResultT;
import com.wb3.meta.config.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

@Slf4j
@Service("goodsOrdersService")
@Transactional(transactionManager = "dataSourceTransactionManagerOne", rollbackFor = Exception.class)
public class GoodsOrdersServiceImpl implements GoodsOrdersService {
    private static final String PREFIX = "ZZ";
    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmm");
    private static final AtomicLong counter = new AtomicLong(0);

    private static final int LOCKED_TIME = 15;  //锁单时间

    @Autowired
    private WxPayService wxService;
    @Autowired
    private GoodsOrdersMapper goodsOrdersMapper;
    @Autowired
    private GoodsInfoService goodsInfoService;

    @Autowired
    private MyToysService myToysService;

    @Autowired
    private RedisUtils redisUtils;

    /**
     * 分页查询方法
     *
     * @param vo
     * @return
     */
    @Override
    public Page<ResGoodsOrdersVo> getModelPage(ReqGoodsOrdersVo vo) {

        PageHelper.startPage(vo.getPageNum(), vo.getPageSize());

        return (Page<ResGoodsOrdersVo>) getModelListByConditions(vo);
    }

    /**
     * 列表查询方法 -返回 res 对象
     *
     * @param vo
     * @return
     */
    @Override
    public List<ResGoodsOrdersVo> getModelListByConditions(ReqGoodsOrdersVo vo) {
        return goodsOrdersMapper.getModelListByConditions(vo);
    }

    /**
     * 根据条件查询单条数据方法，返回res vo类
     *
     * @param vo
     * @return
     */
    @Override
    public ResGoodsOrdersVo getResModelByConditions(ReqGoodsOrdersVo vo) {
        return goodsOrdersMapper.getResModelByConditions(vo);
    }

    /**
     * 根据条件查询单个对象方法
     *
     * @param goodsOrders
     * @return
     */
    @Override
    public GoodsOrders getModelByConditions(GoodsOrders goodsOrders) {
        return null;
    }

    /**
     * 根据id查询单个对象方法
     *
     * @param id
     * @return
     */
    @Override
    public GoodsOrders getModelById(Object id) {
        return goodsOrdersMapper.selectByPrimaryKey(id);
    }

    /**
     * 新增对象方法
     *
     * @param goodsOrders
     */
    @Override
    public void addModel(GoodsOrders goodsOrders) {
        goodsOrders.setCreateTime(new Date().getTime());
        if (goodsOrders.getStatus() == null) {
            goodsOrders.setStatus(EnumConstants.StatusEnum.VALID.getCode());
        }
        goodsOrdersMapper.insertUseGeneratedKeys(goodsOrders);
    }

    /**
     * 更新对象方法
     *
     * @param goodsOrders
     */
    @Override
    public void updateModel(GoodsOrders goodsOrders) {
        goodsOrders.setUpdateTime(new Date());
        goodsOrdersMapper.updateByPrimaryKeySelective(goodsOrders);
    }

    /**
     * 根据id删除对象方法
     *
     * @param id
     */
    @Override
    public void deleteModelById(Object id) {

    }

    /**
     * 获取分页数据，返回 map对象方法
     *
     * @param vo
     * @return
     */
    @Override
    public ResultT getModelMapPage(ReqGoodsOrdersVo vo) {
        return ResultT.success(DataTableUtil.changePage(getModelPage(vo)));
    }

    /**
     * 根据id查询单个对象方法，返回 map对象方法
     *
     * @param id
     * @return
     */
    @Override
    public ResultT getModelMapById(Object id) {
        return null;
    }

    /**
     * 根据条件查询单个对象，返回map对象方法
     *
     * @param goodsOrders
     * @return
     */
    @Override
    public ResultT getModelMapByConditions(GoodsOrders goodsOrders) {
        return null;
    }

    /**
     * 查询列表-map对象
     *
     * @param vo
     * @return
     */
    @Override
    public ResultT getResModelListMapByConditions(ReqGoodsOrdersVo vo) {
        return ResultT.success(goodsOrdersMapper.getModelListByConditions(vo));
    }

    /**
     * 根据条件查询res vo对象，返回map对象方法
     *
     * @param vo
     * @return
     */
    @Override
    public ResultT getResModelMapByConditions(ReqGoodsOrdersVo vo) {
        return ResultT.success(getResModelByConditions(vo));
    }

    /**
     * 更新或插入对象方法
     *
     * @param vo
     * @return
     */
    @Override
    public ResultT saveOrUpdate(ReqGoodsOrdersVo vo) {
        if (vo.getId() != null) {
            updateModel(vo);
        } else {
            addModel(vo);
        }
        return ResultT.success(vo);
    }

    /**
     * 根据条件删除方法
     *
     * @param vo
     * @return
     */
    @Override
    public ResultT delete(ReqGoodsOrdersVo vo) {
        return null;
    }


    @Override
    public synchronized ResultT createOrder(ReqGoodsOrdersVo reqGoodsOrdersVo) {

        if (reqGoodsOrdersVo.getBuyNum() == null || reqGoodsOrdersVo.getBuyNum() == 0) {
            return ResultT.fail("购买数量要大于0");
        }
        if (reqGoodsOrdersVo.getGoodsId() == null) {
            return ResultT.fail("商品id不能为空");
        }
        ReqGoodsInfoVo reqGoodsInfoVo = new ReqGoodsInfoVo();
        reqGoodsInfoVo.setId(reqGoodsOrdersVo.getGoodsId());
        ResGoodsInfoVo resGoodsInfoVo = goodsInfoService.getResModelByConditions(reqGoodsInfoVo);
        if (resGoodsInfoVo == null) {
            return ResultT.fail("未查询到商品");
        }
        if (resGoodsInfoVo.getStatus() != 2) {
            return ResultT.fail("商品非销售状态");
        }
        if (resGoodsInfoVo.getSaleTime().getTime() > new Date().getTime()) {
            return ResultT.fail("未到销售时间");
        }
        if (resGoodsInfoVo.getQuantity() <= 0) {
            return ResultT.fail("商品已售罄");
        }

        reqGoodsOrdersVo.setUserId(RequestHolder.getUserId());
        reqGoodsOrdersVo.setStatus(0);
        List<ResGoodsOrdersVo> resGoodsOrdersVoList = getModelListByConditions(reqGoodsOrdersVo);
        if (!CollectionUtils.isEmpty(resGoodsOrdersVoList)) {
            return ResultT.fail("用户尚有未支付的订单");
        }

        String lockedkeyPrefix = "locked-" + reqGoodsOrdersVo.getGoodsId() + ":";

        AtomicInteger lockedNum = new AtomicInteger(0); //当前锁定的库存
        Set<String> keys = redisUtils.getKeysByPrefix(lockedkeyPrefix);
        if (keys != null) {
            keys.forEach(s -> {
                Integer count = (Integer) redisUtils.get(s);
                if (count != null) {
                    lockedNum.addAndGet(count);
                }
            });
        }
        log.info("商品：{}，总库存量：{}，当前锁定库存：{}", reqGoodsOrdersVo.getGoodsId(), resGoodsInfoVo.getQuantity(), lockedNum.get());
        if (resGoodsInfoVo.getQuantity() - lockedNum.get() < reqGoodsOrdersVo.getBuyNum()) {
            return ResultT.fail("商品库存不足");
        }

        ReqGoodsOrdersVo ordersVo = new ReqGoodsOrdersVo();
        ordersVo.setUserId(RequestHolder.getUserId());
        ordersVo.setBuyQty(reqGoodsOrdersVo.getBuyNum());
        BigDecimal buyPrice = resGoodsInfoVo.getGoodsPrice().multiply(new BigDecimal(reqGoodsOrdersVo.getBuyNum()));
        //如果有折扣，需要进行处理
        if (resGoodsInfoVo.getDiscount() != null) {
            buyPrice = buyPrice.multiply(resGoodsInfoVo.getDiscount()).divide(new BigDecimal(10), RoundingMode.UP);
        }
        ordersVo.setBuyPrice(buyPrice);
        ordersVo.setGoodsId(resGoodsInfoVo.getId());
        ordersVo.setOrderType(0);
        ordersVo.setOrderNo(generateOrderNo());

        if(resGoodsInfoVo.getGoodsPrice().compareTo(BigDecimal.ZERO) > 0){
            ordersVo.setStatus(0);
            String lockedKey = lockedkeyPrefix + RequestHolder.getUserId() + ":";
            redisUtils.set(lockedKey, reqGoodsOrdersVo.getBuyNum(), 60 * LOCKED_TIME);  //库存锁定15分钟
        }else{
            ordersVo.setStatus(2);
            //如果购买的是崽崽，则要给用户添加崽崽
            ResGoodsOrdersVo resGoodsOrdersVo = new ResGoodsOrdersVo();
            BeanUtils.copyProperties(ordersVo,resGoodsOrdersVo);
            myToysService.handleBuyToys(resGoodsOrdersVo);
        }
        saveOrUpdate(ordersVo); //插入订单
        return ResultT.success(ordersVo);
    }

    /**
     * @return void
     * @Author RP
     * @Description // 定时处理未支付订单
     * @Date 12:47 2024/3/31
     * @Param []
     **/
    @Override
    public void handleNoPayOrder() {
        log.info("定时任务：【更改未支付订单-超时-状态】------开始");

//        int result = goodsOrdersMapper.updateOrderCancle(15);
        List<ResGoodsOrdersVo> resGoodsOrdersVoList = goodsOrdersMapper.getOrderCancleList(LOCKED_TIME);
        if (CollectionUtils.isEmpty(resGoodsOrdersVoList)) {
            log.info("当前没有未支付的订单，定时任务结束");
            return;
        }
        resGoodsOrdersVoList.forEach(resGoodsOrdersVo -> {
            cancleOrderTask(resGoodsOrdersVo);
            log.info("已将订单：{}，创建用户：{}，设置为取消状态", resGoodsOrdersVo.getId(), resGoodsOrdersVo.getUserId());
        });
        log.info("定时任务：【更改未支付订单-超时-状态】------结束，本次共更新：{}条", resGoodsOrdersVoList.size());
    }

    /**
     * @param reqGoodsInfoVo
     * @return com.wb3.meta.common.pojo.ResultT
     * @Author RP
     * @Description //崽崽续费
     * @Date 16:01 2024/3/31
     * @Param [reqGoodsOrdersVo]
     */
    @Override
    public ResultT toysRenewal(ReqGoodsInfoVo reqGoodsInfoVo) {
        if (reqGoodsInfoVo.getMyToysId() == null) {
            return ResultT.fail("我的崽崽id不能为空");
        }

        ReqMyToysVo reqMyToysVo = new ReqMyToysVo();
        reqMyToysVo.setId(reqGoodsInfoVo.getMyToysId());
        ResMyToysVo resMyToysVo = myToysService.getResModelByConditions(reqMyToysVo);
        if (resMyToysVo == null) {
            return ResultT.fail("我的崽崽不存在");
        }
        reqGoodsInfoVo.setToysId(resMyToysVo.getToysId());
        ResGoodsInfoVo resGoodsInfoVo = goodsInfoService.getResModelByConditions(reqGoodsInfoVo);
        if (resGoodsInfoVo == null) {
            return ResultT.fail("没有找到对应的商品信息");
        }
        String renewalkey = "renewal-" + resMyToysVo.getId() + RequestHolder.getUserId() + ":";
        String result = (String) redisUtils.get(renewalkey);
        if (StringUtils.isNotBlank(result)) {
            return ResultT.fail("存在未支付续费订单");
        }
        ReqGoodsOrdersVo ordersVo = new ReqGoodsOrdersVo();
        ordersVo.setUserId(RequestHolder.getUserId());
        ordersVo.setBuyQty(1);
        ordersVo.setBuyPrice(new BigDecimal("9.9"));
        ordersVo.setGoodsId(resGoodsInfoVo.getId());
        ordersVo.setStatus(0);
        ordersVo.setOrderType(1);
        ordersVo.setOrderNo(generateOrderNo());
        saveOrUpdate(ordersVo); //插入订单

        redisUtils.set(renewalkey, "-", 60 * LOCKED_TIME);  //锁定15分钟

        return ResultT.success(ordersVo);
    }

    @Override
    public ResultT cancleOrder(ReqGoodsOrdersVo reqGoodsOrdersVo) {
        if (reqGoodsOrdersVo.getId() == null) {
            return ResultT.fail("订单id不能为空");
        }
        ResGoodsOrdersVo resGoodsOrdersVo = getResModelByConditions(reqGoodsOrdersVo);
        if (resGoodsOrdersVo == null) {
            return ResultT.fail("订单不存在");
        }
        cancleOrderTask(resGoodsOrdersVo);
        return ResultT.success();
    }

    private void cancleOrderTask(ResGoodsOrdersVo resGoodsOrdersVo) {
        WxPayOrderCloseRequest wxPayOrderCloseRequest = new WxPayOrderCloseRequest();
        wxPayOrderCloseRequest.setOutTradeNo(resGoodsOrdersVo.getOrderNo());
        try {
            wxService.closeOrder(wxPayOrderCloseRequest);

            resGoodsOrdersVo.setStatus(3);
            updateModel(resGoodsOrdersVo);
        } catch (WxPayException e) {
            e.printStackTrace();
        }
    }

    /**
     * @return java.lang.String
     * @Author RP
     * @Description //生成唯一订单号
     * @Date 15:15 2024/3/29
     * @Param []
     **/
    public static synchronized String generateOrderNo() {
        LocalDateTime now = LocalDateTime.now();
        String formattedDateTime = now.format(FORMATTER);
        long count = counter.incrementAndGet();
        return PREFIX + formattedDateTime + String.format("%04d", count);
    }
}
